using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using C4F.DevKit.Bluetooth.ServiceAndDeviceDiscovery;

namespace ServiceDiscoveryApplication
{
    public partial class Form1 : Form
    {
        List<Device> deviceList = new List<Device>();
        List<RemoteService> serviceList = new List<RemoteService>();
        List<RemoteService> connectedServicesList = new List<RemoteService>();
        
        public Form1()
        {
            InitializeComponent();
        }

        private void cbServiceSearchType_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (cbServiceSearchType.Text == "Discover all services")
            {
                lblServiceTypeText.Visible = false;
                cbServiceType.Visible = false;
            }
            else if (cbServiceSearchType.Text == "Discover by service type")
            {
                lblServiceTypeText.Visible = true;
                cbServiceType.Visible = true;
            }
        }

        private void lstServices_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (lstServices.SelectedIndex != -1)
            {
                try
                {
                    RemoteService selectedService = GetSelectedService();
                    lblServiceName.Text = selectedService.Name;
                    lblServiceDesc.Text = selectedService.Description;

                    if (IsServiceConnected(ref selectedService))
                    {
                        btnConnectSync.Enabled = false;
                        btnConnectAsync.Enabled = false;
                        btnDisconnectAsync.Enabled = true;
                        btnDisconnectSync.Enabled = true;
                    }
                    else
                    {
                        btnConnectSync.Enabled = true;
                        btnConnectAsync.Enabled = true;
                        btnDisconnectAsync.Enabled = false;
                        btnDisconnectSync.Enabled = false;
                    }
                }
                catch
                {
                    MessageBox.Show("An unexpected error occured while getting service information.",
                        "Service Information", MessageBoxButtons.OK, MessageBoxIcon.Error);
                    btnConnectSync.Enabled = true;
                    btnConnectAsync.Enabled = true;
                    btnDisconnectAsync.Enabled = false;
                    btnDisconnectSync.Enabled = false;
                }
            }
        }

        private void btnSearchService_Click(object sender, EventArgs e)
        {
            this.Cursor = Cursors.WaitCursor;
            try
            {
                if (lstDevices.SelectedIndex == -1)
                {
                    MessageBox.Show("Select a device!");
                    return;
                }
                if (cbServiceSearchType.SelectedIndex == -1)
                {
                    MessageBox.Show("Select a Search Type!");
                    return;
                }
                if (cbServiceSearchType.Text == "Discover by service type" && cbServiceType.SelectedIndex == -1)
                {
                    MessageBox.Show("Select a Service Type!");
                    return;
                }

                Device selectedDevice = GetSelectedDevice();

                if (cbServiceSearchType.Text == "Discover by service type")
                {
                    switch (cbServiceType.Text)
                    {
                        case "File Transfer Profile":
                            serviceList = deviceServicesManager1.DiscoverServicesByType(
                                                               selectedDevice,
                                                               ServiceType.OBEXFileTransfer);

                            break;
                        case "Serial Port Profile":
                            serviceList = deviceServicesManager1.DiscoverServicesByType(
                                                               selectedDevice,
                                                               ServiceType.SerialPortProfile);
                            break;
                        case "Object Push Profile":
                            serviceList = deviceServicesManager1.DiscoverServicesByType(
                                                               selectedDevice,
                                                               ServiceType.OBEXObjectPush);
                            break;
                    }
                }
                else
                    serviceList = deviceServicesManager1.DiscoverAllServices(selectedDevice);

                lstServices.Items.Clear();

                if (serviceList != null && serviceList.Count != 0)
                {
                    foreach (RemoteService service in serviceList)
                    {
                        if (!string.IsNullOrEmpty(service.Name))
                            lstServices.Items.Add(service.Name);
                    }
                }

                if (serviceList == null || serviceList.Count == 0 || lstServices.Items.Count ==0)
                {
                    MessageBox.Show("No service was found.", "Service Discovery",
                        MessageBoxButtons.OK, MessageBoxIcon.Information);
                }
            }
            catch
            {
                MessageBox.Show("An unexpected error was raised during service discovery.",
                    "Service Discovery", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
            finally
            {
                btnConnectAsync.Enabled = false;
                btnConnectSync.Enabled = false;
                btnDisconnectAsync.Enabled = false;
                btnDisconnectSync.Enabled = false;
                this.Cursor = Cursors.Default;
            }
        }

        private void btnSearchDevices_Click(object sender, EventArgs e)
        {

            //Discover all devices.
            try
            {
                InitializeForm();
                this.Cursor = Cursors.WaitCursor;
                deviceList = deviceServicesManager1.DiscoverAllDevices();
                if (deviceList != null && deviceList.Count != 0)
                {
                    foreach (Device device in deviceList)
                    {
                        lstDevices.Items.Add(device.Name);
                    }

                }
                else
                {
                    MessageBox.Show("No device was found.",
                                    "Device Discovery", MessageBoxButtons.OK, MessageBoxIcon.Information);
                }

            }
            catch
            {
                MessageBox.Show("An unexpected error was raised during device discovery.",
                    "Device Discovery", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
            finally
            {
                this.Cursor = Cursors.Default;
            }
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            btnSearchDevices_Click(sender, e);
        }

        private void InitializeForm()
        {
            lstDevices.Items.Clear();
            lstServices.Items.Clear();
            cbServiceSearchType.SelectedIndex = -1;
            cbServiceType.SelectedIndex = -1;
            cbServiceSearchType.Enabled = false;
            cbServiceType.Enabled = false;
            btnSearchService.Enabled = false;
            btnConnectSync.Enabled = false;
            btnConnectAsync.Enabled = false;
            btnDisconnectSync.Enabled = false;
            btnDisconnectSync.Enabled = false;
            deviceList.Clear();
            serviceList.Clear();
            lblServiceName.Text = string.Empty;
            lblServiceDesc.Text = string.Empty;
        }

        private void lstDevices_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (lstDevices.SelectedIndex != -1)
            {
                cbServiceSearchType.Enabled = true;
                cbServiceType.Enabled = true;
                lstServices.Enabled = true;
                btnSearchService.Enabled = true;
                lstServices.Items.Clear();
                lblServiceName.Text = string.Empty;
                lblServiceDesc.Text = string.Empty;
                btnConnectSync.Enabled = false;
                btnConnectAsync.Enabled = false;
                btnDisconnectSync.Enabled = false;
                btnDisconnectSync.Enabled = false;
                serviceList.Clear();
            }
        }

        private void btnConnectSync_Click(object sender, EventArgs e)
        {
            this.Cursor = Cursors.WaitCursor;
            RemoteService selectedService = null;
            btnConnectSync.Enabled = false;
            btnConnectAsync.Enabled = false;

            try
            {
                selectedService = GetSelectedService();
                selectedService.Connected -= 
                    new RemoteService.ConnectionEventHandler(selectedService_AsyncConnected);
                selectedService.Connect();
                MessageBox.Show("Synchronous Connection to service " + selectedService.Name + " successful!");
                connectedServicesList.Add(selectedService);
                btnDisconnectSync.Enabled = true;
                btnDisconnectAsync.Enabled = true;
            }
            catch (ServiceConnectionException servEx)
            {

                MessageBox.Show("An error occurred during Synchronous Connection to "
                + selectedService.Name + Environment.NewLine + "Error Details: " + servEx.Message,
                "Service Connection", MessageBoxButtons.OK, MessageBoxIcon.Error);
                btnConnectSync.Enabled = true;
                btnConnectAsync.Enabled = true;
                btnDisconnectSync.Enabled = false;
                btnDisconnectAsync.Enabled = false;
            }
            catch
            {
                MessageBox.Show("An unexpected error was raised during Synchronous Connection to "
                    + selectedService.Name, "Service Connection", MessageBoxButtons.OK, MessageBoxIcon.Error);
                btnConnectSync.Enabled = true;
                btnConnectAsync.Enabled = true;
                btnDisconnectSync.Enabled = false;
                btnDisconnectAsync.Enabled = false;
            }
            finally
            {
                this.Cursor = Cursors.Default;
            }
        }

        void selectedService_AsyncConnected(object sender, ConnectionEventArgs e)
        {
            RemoteService selectedService = sender as RemoteService;

            if (selectedService != null && e.Error == null)
            {
                MessageBox.Show("Asynchronous connection to service " + selectedService.Name + " successful!");
                connectedServicesList.Add(selectedService);
                btnDisconnectSync.Enabled = true;
                btnDisconnectAsync.Enabled = true;
            }
            else
            {
                MessageBox.Show("An unexpected error was raised during Asynchronous Connection to "
                      + selectedService.Name + Environment.NewLine + "Error Details: " + e.Error.Message,
                      "Service Connection", MessageBoxButtons.OK, MessageBoxIcon.Error);
                btnConnectSync.Enabled = true;
                btnConnectAsync.Enabled = true;
                btnDisconnectSync.Enabled = false;
                btnDisconnectAsync.Enabled = false;
            }

        }

        private void btnConnectAsync_Click(object sender, EventArgs e)
        {
            this.Cursor = Cursors.WaitCursor;
            RemoteService selectedService = null;
            btnConnectSync.Enabled = false;
            btnConnectAsync.Enabled = false;
            try
            {
                selectedService = GetSelectedService();
                // If there is a handler already, remove it and add it again.
                selectedService.Connected -=
                    new RemoteService.ConnectionEventHandler(selectedService_AsyncConnected);
                selectedService.Connected += 
                    new RemoteService.ConnectionEventHandler(selectedService_AsyncConnected);
                selectedService.ConnectAsync(Guid.NewGuid());
            }
            catch (ServiceConnectionException servEx)
            {
                MessageBox.Show("An error occurred during Asynchronous Connection to " +
                    selectedService.Name + Environment.NewLine + "Error Details: " + servEx.Message,
                    "Service Connection", MessageBoxButtons.OK, MessageBoxIcon.Error);
                btnConnectSync.Enabled = true;
                btnConnectAsync.Enabled = true;
                btnDisconnectSync.Enabled = false;
                btnDisconnectAsync.Enabled = false;
            }
            catch(Exception ex)
            {
                MessageBox.Show("An unexpected error occurred during Asynchronous Connection to " +
                    selectedService.Name + Environment.NewLine + "Error Details: " + ex.Message,
                    "Service Connection", MessageBoxButtons.OK, MessageBoxIcon.Error);
                btnConnectSync.Enabled = true;
                btnConnectAsync.Enabled = true;
                btnDisconnectSync.Enabled = false;
                btnDisconnectAsync.Enabled = false;
            }
            finally
            {
                this.Cursor = Cursors.Default;
            }
        }

        private void btnDisconnectSync_Click(object sender, EventArgs e)
        {
            this.Cursor = Cursors.WaitCursor;
            RemoteService selectedService = null;
            btnDisconnectSync.Enabled = false;
            btnDisconnectAsync.Enabled = false;

            try
            {
                selectedService = GetSelectedService();
                bool isConnected = IsServiceConnected(ref selectedService);
                if (isConnected)
                {
                    selectedService.Disconnected -= 
                        new RemoteService.DisconnectionEventHandler(selectedService_AsyncDisconnected);
                    selectedService.Disconnect();
                }
                MessageBox.Show("Synchronous Disconnection from service " + selectedService.Name + " successful!");
                connectedServicesList.Remove(selectedService);
                btnConnectSync.Enabled = true;
                btnConnectAsync.Enabled = true;
            }
            catch
            {
                MessageBox.Show("An unexpected error was raised during Synchronous Disonnection to "
                    + selectedService.Name, "Service Disconnection", MessageBoxButtons.OK, MessageBoxIcon.Error);
                btnConnectSync.Enabled = false;
                btnConnectAsync.Enabled = false;
                btnDisconnectSync.Enabled = true;
                btnDisconnectAsync.Enabled = true;
            }
            finally
            {
                this.Cursor = Cursors.Default;
            }
        }

        void selectedService_AsyncDisconnected(object sender, DisconnectionEventArgs e)
        {
            RemoteService selectedService = sender as RemoteService;
            if (selectedService != null && e.Error == null)
            {
                MessageBox.Show("Asynchronous disconnection from service " + selectedService.Name + " successful!");
                connectedServicesList.Remove(selectedService);
                btnConnectSync.Enabled = true;
                btnConnectAsync.Enabled = true;
            }
            else
            {
                MessageBox.Show("An unexpected error was raised during Asynchronous Disconnection to "
                    + selectedService.Name, "Service Disconnection", MessageBoxButtons.OK, MessageBoxIcon.Error);
                btnConnectSync.Enabled = false;
                btnConnectAsync.Enabled = false;
                btnDisconnectSync.Enabled = true;
                btnDisconnectAsync.Enabled = true;
            }
        }

        private void btnDisconnectAsync_Click(object sender, EventArgs e)
        {
            this.Cursor = Cursors.WaitCursor;
            RemoteService selectedService = null;
            btnDisconnectSync.Enabled = false;
            btnDisconnectAsync.Enabled = false;

            try
            {
                selectedService = GetSelectedService();
                bool isConnected = IsServiceConnected(ref selectedService);
                if (isConnected)
                {
                    // If there is a handler already, remove it and add it again.
                    selectedService.Disconnected -=
                        new RemoteService.DisconnectionEventHandler(selectedService_AsyncDisconnected);
                    selectedService.Disconnected +=
                        new RemoteService.DisconnectionEventHandler(selectedService_AsyncDisconnected);
                    selectedService.DisconnectAsync(Guid.NewGuid());
                }               
            }
            catch
            {
                MessageBox.Show("An unexpected error was raised during Asynchronous Disconnection to "
                    + selectedService.Name, "Service Disconnection", MessageBoxButtons.OK, MessageBoxIcon.Error);
                btnConnectSync.Enabled = false;
                btnConnectAsync.Enabled = false;
                btnDisconnectSync.Enabled = true;
                btnDisconnectAsync.Enabled = true;
            }
            finally
            {
                this.Cursor = Cursors.Default;
            }
        }

        private Device GetSelectedDevice()
        {
            foreach (Device device in deviceList)
            {
                if (lstDevices.Items.Contains(device.Name) && device.Name == lstDevices.Text)
                    return device;
            }
            throw new Exception("Device could not be found.");
        }

        private RemoteService GetSelectedService()
        {
            foreach (RemoteService service in serviceList)
            {
                if (lstServices.Items.Contains(service.Name) && service.Name == lstServices.Text)
                    return service;
            }
            throw new Exception("Service could not be found.");
        }

        private bool IsServiceConnected(ref RemoteService service)
        {
            foreach (RemoteService connectedService in connectedServicesList)
            {
                if (connectedService.Name == service.Name &&
                    connectedService.Description == service.Description &&
                    connectedService.DeviceAddress.Address == service.DeviceAddress.Address)
                {
                    service = connectedService;
                    return true;
                }
            }
            return false;
        }
    }
}